home *** CD-ROM | disk | FTP | other *** search
- ;------------------------------------------------------------------------;
- ; ANSI.COM - Replacement for the ANSI.SYS console device driver. ;
- ; Unlike ANSI.SYS which must be installed at boot time, ANSI.COM ;
- ; can be installed and uninstalled at anytime. Enhancements include ;
- ; a fast screen write and variable sized keyboard reassignment buffer. ;
- ; ;
- ; Update 3/2/89 - Fix for DOS function 0Bh, Check Standard Input Status ;
- ; and STDIN in ANSI_INT_21 handler. ;
- ; Leading zero inserted for Device Status Report for ;
- ; single digit cursor positions. ;
- ; INFORMATION typo 40 for 40H. ;
- ; WRITE_FAST modified to handle CR and LF instead of ;
- ; WRITE_CHAR. ;
- ; Update 3/7/89 - Fix for CLS in graphics mode. Version 1.2 ;
- ; ;
- ; Update 8/8/89 - STI added to INT 21 and 29 handler. Version 1.3 ;
- ;: ;
- ;: Update 01/01/90 - [KON | KOFF] and [PON | POFF] added Version 1.31 ;
- ;: (all changes marked with ;: - Gary Meeker) ;
- ;| Update 03/23/90 - /Q option added for no output when exectued 1.32 ;
- ;| (all changes marked with ;| - Gary Meeker) ;
- ;; Update 05/16/90 - removed Syntax from output unless needed 1.33 ;
- ;; added /T test for load. ;
- ;; (all changes marked with ;; - Gary Meeker) ;
- ;. Update 10/28/90 - Added /P nn top of screen protection mode 1.34 ;
- ;. (all changes marked with ;. - Gary Meeker) ;
- ;@ Update 12/01/90 - Added PCBoard @X## color code support 1.35 ;
- ;@ also added @Variable@ Support ;
- ;@ added /S to load stats data from file ;
- ;@ (all changes marked with ;@ - Gary Meeker) ;
- ;& ;
- ;& Update 12/12/90 - My mistake, I didn't realize @X00 saved 1.36 ;
- ;& the color and @XFF restored it. Works now. ;
- ;& Also made prompts return to start of line ;
- ;& when cleared (like PCBoard does) & QON ;
- ;& now changes @MORE@ & @PAUSE@ into @WAIT@ ;
- ;& (all changes marked with ;& - Gary Meeker) ;
- ; ;
- ;$ Update 4/22/91 - Change set cursor routine. If new position 1.37 ;
- ;$ is off the screen use the last row or column. ;
- ;$ Added switch to not include PCB code. ;
- ;$ Corrected syntax display. ;
- ;$ Modified CLS to honor protected (/P) lines. ;
- ;$ Modified /T to returned status switches. ;
- ;$ Modified /P to accept * to mean current row-1. ;
- ;$ (all changes marked with ;$ - Wayne Mingee) ;
- ; ;
- ;+ Update 9/19/91 - Allow ESC[p to clear all KB reassigns and 1.38 ;
- ;+ ESC[np to clear single key reassign. ;
- ;+ ie: ESC[65p will reset ascii 65 to it's default [A] ;
- ; ;
- ;^ Update 01/01/92 - Added XON/XOFF to control @X## color codes 1.39 ;
- ;^ added support for finding relocated copies. ;
- ;^ This should allow LOADHI under DOS 5 or QRAM/QEMM ;
- ;^ (all changes marked with ;^ - Gary Meeker) ;
- ;^ (Was added to my 1.37 version 01/09/91 but now ;
- ;^ incorporated into this version as 1.39 to include ;
- ;^ changes by Wayne Mingee) ;
- ; ;
- ; PC Magazine - Michael J. Mefford ;
- ;------------------------------------------------------------------------;
-
- PCB equ 1 ;$ 1 = if PCB code wanted
-
- _TEXT SEGMENT PUBLIC 'CODE'
- ASSUME CS:_TEXT,DS:_TEXT,ES:_TEXT,SS:_TEXT
- ORG 100H
- START: JMP INITIALIZE
-
- ; DATA AREA
- SIGNATURE DB CR,SPACE,SPACE,SPACE,CR,LF
- COPYRIGHT DB "ANSI 1.3i (C) 1988 Ziff Communications Co.",CR,LF ;^
- PROGRAMMER DB "PC Magazine ",BOX," Michael J. Mefford",CR,LF,LF,"$"
- DB CTRL_Z
-
- CR EQU 13
- LF EQU 10
- CTRL_Z EQU 26
- SPACE EQU 32
- BOX EQU 254
- ESC_CHAR EQU 27
- SINGLE_QUOTE EQU 39
- DOUBLE_QUOTE EQU 34
- BELL EQU 7
- BS EQU 8
- TAB EQU 9
-
- OFF EQU 1
- ON EQU 2
- SLOW EQU 4
- FAST EQU 8
- KOFF EQU 16 ;:
- KON EQU 32 ;:
- POFF EQU 64 ;:
- PON EQU 128 ;:
- XOFF EQU 256 ;^
- XON EQU 512 ;^
- STATUS_MASK EQU 1111110000000001B ;: Set Mask and Bit
- AND_MASK EQU 1111111111111100B ;^ Set Mask
- OR_MASK EQU 0000000000000001B ;^ Set Bit
-
- ANSI_STATE DW ESC_STATE
- STATUS DW ON OR FAST OR KON OR PON OR XON ;: ;^
- PARAMETERS DB "OFF",0,"ON",0,0,"SLOWFASTKOFFKON",0,"POFFPON",0 ;:
- DB "XOFFXON",0 ;^
- LAST_PARAMETER EQU $ - PARAMETERS
-
- multiplex_id db 0dbh ;^ Program ID for multiplex int
- dos_version dw 0 ;^ DOS Version number
- int2fh dd -1 ;^ Int 2f vector (DOS MULTIPLEX)
- OLD_INT_29 DW ?,?
- OLD_INT_16 DW ?,?
- OLD_INT_21 DW ?,?
- if PCB ;$
- OLD_INT_08 DW ?,? ;@ Save Timer Interupt
- endif ;$
- ATTRIBUTE DB 7
- if PCB ;$
- SAVE_ATTRIBUTE DB ? ;& For saving attribute
- endif ;$
- SAVE_POSITION DW 0
- LINE_WRAP DB ON
- QUOTE_TYPE DB ?
- ESC_COUNT DW 0
- NUMBER_COUNT DW 0
-
- COMMAND_TABLE LABEL BYTE
- DB "H", "A", "B", "C", "D", "f", "n", "s", "u", "K", "m", "h", "l", "p", "J"
- COMMAND_LENGTH EQU $ - COMMAND_TABLE
-
- DW CURS_POSITION, CURSOR_UP, CURSOR_DOWN, CURS_FORWARD, CURS_BACKWARD
- DW HORZ_VERT_POS, DEVICE_STATUS, SAVE_CURSOR, RESTORE_CURS, ERASE_IN_LINE
- DW SGR, SET_MODE, RESET_MODE, REASSIGNMENT, CLS
- COMMAND_END EQU $ - 2
-
- ATTRIBUTE_TABLE LABEL BYTE
- DB 00,01,04,05,07,08,30,31,32,33,34,35,36,37,40,41,42,43,44,45,46,47
- ATTRIBUTE_LENGTH EQU $ - ATTRIBUTE_TABLE
-
- ;Format: AND mask,OR mask
- DB 000H,07H, 0FFH,08H, 0F8H,01H, 0FFH,80H, 0F8H,70H, 088H,00H
- DB 0F8H,00H, 0F8H,04H, 0F8H,02H, 0F8H,06H, 0F8H,01H, 0F8H,05H
- DB 0F8H,03H, 0F8H,07H, 08FH,00H, 08FH,40H, 08FH,20H, 08FH,60H
- DB 08FH,10H, 08FH,50H, 08FH,30H, 08FH,70H
- ATTRIBUTE_END EQU $ - 2
-
- if PCB ;$
- AT_VARIABLE_TABLE LABEL BYTE ;@
- DB '@CLS@CLREOL@AUTOMORE@POFF@PON@QOFF@QON@BEEP@MORE@PAUSE@WAIT@HANGUP@' ;@
- DB 'OPTEXT@FIRSTU@FIRST@USER@CITY@HOMEPHONE@DATAPHONE@PROLTR@PRODESC@' ;@
- DB 'EXPDATE@LASTDATEON@LASTTIMEON@INCONF@CONFNAME@BOARDNAME@' ;@
- DB 'LASTCALLERNODE@LASTCALLERSYSTEM@EVENT@SYSOPIN@SYSOPOUT@BPS@NODE@' ;@
- DB 'SYSDATE@SYSTIME@FILERATIO@BYTERATIO@' ;@
- DB 'SECURITY@NUMCALLS@NUMTIMESON@TIMELEFT@TIMELIMIT@TIMEUSED@TOTALTIME@' ;@
- DB 'BYTESLEFT@BYTELIMIT@DLFILES@UPFILES@KBLEFT@KBLIMIT@CONFNUM@' ;@
- DB 'CURMSGNUM@HIGHMSGNUM@LOWMSGNUM@MSGREAD@MSGLEFT@NUMBLT@NUMDIR@' ;@
- DB 'DAYBYTES@MINLEFT@DLBYTES@UPBYTES@EXPDAYS@' ;@
-
- LAST_VARIABLE EQU $ - 1 ;@
-
- JUMP_TABLE LABEL WORD ;@
- DW CLS, ERASE_IN_LINE, AUTOMORE, AUTOOFF, AUTOOFF, QOFF, QON ;&;@
- DW BEEP, MORE, PAUSE, WAIT1, SKIP_IT ;@
-
- SUB_TABLE LABEL BYTE ;@
- DB 8,15,15,25,24,13,13,1,47 ;@
- DB 8,8,5,33,13,63 ;@
- DB 52,52,5,5,5,5,2 ;@
- DB 0,0,4,4 ;@
- DB 2,4,2,2,2,2,2 ;@
- DB 4,4,2,2,4,4,2 ;@
- DB 4,4,4,4,4,2,2 ;@
- DB 4,2,4,4,2 ;@
-
- SUB_LIST LABEL BYTE ;@
- DB '!OPTEXT!' ;@ OPTTEXT
- DB 'GARY',0,0,0,0,0,0,0,0,0,0,0 ;@ FirstU
- DB 'Gary',0,0,0,0,0,0,0,0,0,0,0 ;@ First
- DB 'GARY MEEKER',0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;@ User
- DB 'LAWRENCEVILLE, GA',0,0,0,0,0,0,0 ;@ City
- DB '404 995-2699',0 ;@ HomePhone
- DB '404 962-1788',0 ;@ DataPhone
- DB 'Z' ;@ Proltr
- DB 'Zmodem (Batch U/L and D/L)', 15 DUP (0) ;@ ProDesc
- DB '01-01-91' ;@ ExpDate
- DB '12-01-90' ;@ LastDateOn
- DB '08:00' ;@ LastTimeOn
- DB 'Magazine (1) Conference ',0,0,0,0,0,0,0,0,0 ;@ InConf
- DB 'Magazine',0,0,0,0,0 ;@ ConfName
- DB 'SHARP Technical Support Line BBS', 31 DUP (0) ;@ BoardName
- DB 'MIKE BATE (RIVERDALE, GA)', 27 DUP (0) ;@ LastCallerNode
- DB 'GARY MEEKER (LAWRENCEVILLE, GA)', 21 DUP (0) ;@ LastCallerSystem
- DB '04:30' ;@ Event
- DB '08:30' ;@ SysopIn
- DB '17:00' ;@ SysopOut
- DB '2400',0 ;@ bps
- DB '1',0 ;@ Node
-
- DD 48 ;@ FileRatio
- DD 128 ;@ ByteRatio
-
- DW 120 ;@ Security
- DD 23946 ;@ numcalls
- DW 2107 ;@ numtimeson
- DW 61 ;@ timeleft
- DW 121 ;@ timelimit
- DW 59 ;@ timeused
- DW 59 ;@ totaltime
- DD 9508313 ;@ bytesleft
- DD 10238976 ;@ bytelimit
- DW 44 ;@ dlfiles
- DW 1234 ;@ upfiles
- DD 9285 ;@ KBLeft
- DD 9999 ;@ KBLimit
- DW 1 ;@ ConfNum
- DD 4734 ;@ CurMsgNum
- DD 4745 ;@ HighMsgNum
- DD 2 ;@ LowMsgNum
- DD 3456 ;@ MsgRead
- DD 987 ;@ MsgLeft
- DW 20 ;@ NumBlt
- DW 31 ;@ NumDir
- DD 30663 ;@ DayBytes
- DW 61 ;@ MinLeft
- DD 730663 ;@ DLBytes
- DD 12345678 ;@ UpBytes
- DW 0 ;@ ExpDays
- SUB_LENGTH EQU $ - SUB_LIST
-
- PAUSE_TIMER DW 182 ;@
- PAUSE_DELAY DW 182 ;@ 10 Seconds
- MORE_DELAY DW 182 * 12 ;@ 2 Minute
- WAIT_DELAY DW 182 * 12 ;@ 2 Minute
-
- WAIT_PROMPT DB 'press enter to continue' ;@
- WAIT_LENGTH DW $ - WAIT_PROMPT ;@
- MORE_PROMPT DB '(61 min left), (H)elp, More?' ;@
- MORE_LENGTH DW $ - MORE_PROMPT ;@
- COMMA DB 0 ;@
- Q_STATE DB 0 ;&
- endif ;$
-
- BIOS_ACTIVE_PAGE EQU 62H
- ACTIVE_PAGE DB ?
- ADDR_6845 DW ?
- BIOS_CRT_MODE EQU 49H
- CRT_MODE DB ?
- CRT_COLS DW ?
- CRT_LEN DW ?
- CRT_START DW ?
- CRT_DATA_LENGTH EQU $ - CRT_MODE
- CURSOR_POSN LABEL WORD
- CURSOR_COL DB ?
- CURSOR_ROW DB ?
- CRT_ROWS DB ?
-
- START_SCROLL DB 0 ;. Number of rows to protect from scrolling up
-
- DOS_INPUT DB OFF
- BUSY_FLAG DB OFF
- REASSIGN_FLAG DB OFF
- REMOVE_FLAG DB ON
- REASSIGN_COUNT DW 0
- REASSIGN_POS DW ?
- FUNCTION_16 DB ?
- ZR EQU 1000000B
-
- ESC_BUFFER_SIZE EQU 126
- REASSIGNMENT_DEFAULT EQU 200
- REASSIGNMENT_SIZE DW REASSIGNMENT_DEFAULT
- REASSIGNMENT_MAX EQU 60 * 1024
- REASSIGN_END DW REASSIGNMENT_BUFFER
- BUFFER_END DW REASSIGNMENT_BUFFER + REASSIGNMENT_DEFAULT
-
- ; CODE AREA
- ;************* INTERRUPT HANDLERS *************;
- ;------------------------------------------------------------------------------;
- ; INT 29 is an undocumented interrupt called by DOS for output to the console. ;
- ;------------------------------------------------------------------------------;
-
- ANSI_INT_29 PROC FAR
- STI
- PUSH AX ;Save all registers.
- PUSH BX
- PUSH CX
- PUSH DX
- PUSH SI
- PUSH DI
- PUSH DS
- PUSH ES
- PUSH BP
-
- CLD ;All string operations forward.
- MOV BX,CS ;Point to our data segment.
- MOV DS,BX
- MOV ES,BX
- CALL ANSI_STATE ;Call the current state of
- ; the ANSI Esc sequence.
- POP BP
- POP ES
- POP DS
- POP DI
- POP SI
- POP DX
- POP CX
- POP BX
- POP AX ;Restore all registers and
- IRET ; and return
- ANSI_INT_29 ENDP
-
- ;------------------------------------------------;
-
- ANSI_INT_21 PROC FAR
- PUSHF
- CMP AH,0BH ;If DOS function 0Bh (Check
- JNZ CK_INPUT ; Standard Input Status)
- CMP CS:REASSIGN_FLAG,ON ; and reassignment in progress,
- JNZ CK_INPUT ; including a Device Status
- CALL DWORD PTR CS:OLD_INT_21 ; Request, then process call in
- MOV AL,0FFH ; case control break pressed;
- IRET ; then return 0FFh for char ready
-
- CK_INPUT: CMP AH,3FH ;Read from STDIN?
- JNZ CK_CONSOLE
- OR BX,BX
- JZ INPUT
-
- CK_CONSOLE: CMP AH,0AH ;If DOS Int 21 functions Ah,
- JZ INPUT ; 7h, 1h or console input (6h)
- CMP AH,7 ; then tell INT 16, DOS input
- JZ INPUT ; is active.
- CMP AH,1
- JZ INPUT
- CMP AH,8
- JZ INPUT
- CMP AH,6
- JNZ QUICK21_EXIT
- CMP DL,0FFH
- JZ INPUT
- QUICK21_EXIT: POPF ;If not, let the original
- JMP DWORD PTR CS:OLD_INT_21 ; interrupt process the call.
-
- INPUT: POPF
- MOV CS:DOS_INPUT,ON ;INT 16 handler flag.
- PUSHF
- CALL DWORD PTR CS:OLD_INT_21 ;Emulate an interrupt.
- MOV CS:DOS_INPUT,OFF ;Turn flag back off.
- STI
- RET 2 ;Return with current flags.
- ANSI_INT_21 ENDP
-
- ;-----------------------------------------------------------------;
- ; If we get here via a DOS console input call, any awaiting key ;
- ; in keyboard buffer is checked to see if it is to be reassigned. :
- ;-----------------------------------------------------------------;
-
- ANSI_INT_16 PROC FAR
- STI ;Interrupts back on.
- PUSHF ;Preserve flags on stack.
- PUSH BP
- PUSH DS
- PUSH AX
- PUSH CS ;Point to our data.
- POP DS
-
- CMP DOS_INPUT,OFF ;If not called via a DOS
- JZ QUICK16_EXIT ; console input call, exit.
- CMP BUSY_FLAG,ON ;If already processing a call,
- JZ QUICK16_EXIT ; exit.
- CLD ;All string operations forward.
- MOV BP,SP ;Base reference to flags on stack
- MOV FUNCTION_16,AH ;Save function request.
- AND AH,NOT 10H ;Strip possible extended request.
- JZ GET_KEY ;If zero, it's wait for a key.
- DEC AH ;Else, decrement. If zero it's
- JZ KEY_STATUS ; key status, else exit.
-
- QUICK16_EXIT: POP AX ;Restore registers and let
- POP DS ; original interrupt handler
- POP BP ; process the call.
- POPF
- JMP DWORD PTR CS:OLD_INT_16
-
- KEY_STATUS: OR BYTE PTR [BP+6],ZR ;Assume none ready; ZR = 1.
- GET_KEY: MOV BUSY_FLAG,ON ;Non-reentrant; flag busy.
- POP AX
- PUSH BX ;Save some more registers.
- PUSH CX
- PUSH DX
- PUSH SI
- PUSH DI
- CMP REASSIGN_FLAG,ON ;Already in process of reassign?
- JZ CK_BUFFER ;If yes, check kbd buffer.
-
- PUSHF ;Else, emulate an interrupt.
- CALL DWORD PTR OLD_INT_16
- PUSHF ;Status call results in flags.
- TEST FUNCTION_16,1 ;Was it a status call?
- JZ CK_DUP ;If no, check key returned.
- POPF ;Else, retrieve status results.
- JZ INT16_EXIT ;If zero, no key waiting.
- AND BYTE PTR [BP+6],NOT ZR ;Else, ZR = 0.
- PUSHF ;PUSHF just to keep stack right.
-
- CK_DUP: POPF ;Fix stack.
- TEST STATUS,KOFF ;:If KOFF then we don't do
- JNZ INT16_EXIT ;:re-assignments
- MOV BX,AX ;Match procedure wants key in BX.
- CALL CK_MATCH ;Check reassignment buffer.
- JC INT16_EXIT ;If no match, exit.
- MOV AX,[DI] ;Else, retrieve string length.
- SUB AX,3 ;Adjust for length word and match
- ADD DI,3 ; byte; same for string pointer.
- OR BL,BL ;Extended key? ie. key = 0.
- JNZ STORE_COUNT ;If no, save length and pointer.
- DEC AX ;Else, adjust for extended code.
- INC DI
- STORE_COUNT: MOV REASSIGN_COUNT,AX ;Save string length.
- MOV REASSIGN_POS,DI ;Save pointer to string.
- MOV REASSIGN_FLAG,ON ;Flag that replacement in effect.
- CK_BUFFER: TEST FUNCTION_16,1 ;Was it a key wait function call?
- JNZ RETRIEVE ;If no, key status; get it.
- CMP REMOVE_FLAG,OFF ;Removed it from kbd buffer?
- JZ RETRIEVE ;If yes, get reassignment.
- MOV AH,FUNCTION_16 ;Else, eat the replaced character
- INT 16H ; via INT 16.
- MOV REMOVE_FLAG,OFF ;Flag character eaten.
-
- RETRIEVE: MOV DI,REASSIGN_POS ;Retrieve pointer to string.
- MOV AX,[DI] ;Retrieve replacement character.
- TEST FUNCTION_16,1 ;Is it a key wait function call?
- JZ REMOVE ;If yes, bump pointer up one.
- AND BYTE PTR [BP+6],NOT ZR ;If no, status call; ZR = 0
- JMP SHORT INT16_EXIT ;All done.
-
- REMOVE: INC REASSIGN_POS ;Move pointer to next character.
- DEC REASSIGN_COUNT ;One less character to replace.
- JZ REASSIGN_DONE ;If end of string, reset flags.
- OR AL,AL ;Else, extended replacement?
- JNZ INT16_EXIT ;If no, done here.
- INC REASSIGN_POS ;Else adjust pointers.
- DEC REASSIGN_COUNT
- JNZ INT16_EXIT ;End of string?
- REASSIGN_DONE: MOV REASSIGN_FLAG,OFF ;If yes, reset flags.
- MOV REMOVE_FLAG,ON
-
- INT16_EXIT: MOV BUSY_FLAG,OFF ;Reset the busy flag.
- POP DI ;Restore registers.
- POP SI
- POP DX
- POP CX
- POP BX
- POP DS
- POP BP
- POPF ;Flags on stack have status
- RET 2 ; results; kill old flags.
- ANSI_INT_16 ENDP
- if PCB ;$
- ANSI_INT_08 PROC FAR ;@
- CMP CS:[PAUSE_TIMER],0 ;@
- JE SKIP_TIMER ;@
- DEC CS:[PAUSE_TIMER] ;@
- SKIP_TIMER: JMP DWORD PTR CS:OLD_INT_08 ;@
- ANSI_INT_08 ENDP ;@
- endif ;$
- ;^============================================================================
- ;^ MUXINT processes calls to interrupt 2Fh
- ;^ Entry: AH - Device ID
- ;^ Exit: AL - 0FFh if AH = Alias device ID. Unchanged otherwise.
- ;^ ES - Code segment if AH = Alias device ID. Unchanged otherwise.
- ;^============================================================================
- muxint proc far ;^
- cmp ah,cs:[multiplex_id] ;^ Check for program ID
- je muxint_1 ;^ Its us, indicate installed.
- jmp cs:[int2fh] ;^ else pass the call on
- muxint_1: ;^
- mov al,-1 ;^ Indicate Alias installed
- push cs ;^ ES = installed code segment
- pop es ;^
- iret ;^
- muxint endp ;^
-
- ;************* ANSI ESCAPE STATE ROUTINES ************* ;
-
- ESC_STATE: MOV BX,OFFSET BRACKET_STATE ;Assume Esc character.
- CMP AL,ESC_CHAR ;Is it Esc? If yes, store
- JZ SHORT_JUMP ; char. and next state.
- if PCB ;$
- CMP DOS_INPUT,ON ;@ Called via DOS Input?
- JE WRITE_CHAR2 ;@ Yes, Nevermind
- MOV BX,OFFSET ATX_STATE ;@ No, Assume @ Character
- CMP AL,"@" ;@ Is it @? If yes, store
- JZ SHORT_JUMP ;@ char. and next state.
- WRITE_CHAR2:
- endif ;$
- JMP WRITE_CHAR ;@ Else, normal char; write it.
- ;------------------------------------------------;
-
- BRACKET_STATE: MOV BX,OFFSET SPECIAL_STATE ;Assume left bracket.
- CMP AL,"[" ;Is it left bracket? If yes,
- SHORT_JUMP: JZ STORE_STATE ;store char. and next state.
- JMP FLUSH_BUFFER ;Else, flush Esc out of buffer.
-
- ;---------------------------------------------------------------;
- ; Must process <ESC>[2J (CLS) regardless if ANSI.COM ON or OFF. ;
- ;---------------------------------------------------------------;
-
- SPECIAL_STATE: MOV BX,OFFSET CLS_STATE ;Assume Erase in Display code.
- CMP AL,"2" ;Is it the "2" ?
- JZ STORE_STATE ;If yes, progress to next state.
- TEST STATUS,OFF ;Else, is ANSI OFF ?
- JNZ FLUSH_BUFFER ;If yes, flush Esc, bracket.
- MOV BX,OFFSET PARAM_STATE ;Else, check for first Set,
- CMP AL,"=" ; Reset Mode characters of
- JZ STORE_STATE ; "=" and "?".
- CMP AL,"?"
- JZ STORE_STATE ;If found, store.
- JMP SHORT DO_PARAMETER ;Else, check other codes.
-
- ;------------------------------------------------;
-
- CLS_STATE: CMP AL,"J" ;Is it second character of CLS?
- MOV DI,OFFSET COMMAND_END ;If yes, execute
- JZ EXECUTE ; Erase in Display procedure.
- TEST STATUS,OFF ;ANSI OFF? If yes, flush buffer.
- JNZ FLUSH_BUFFER ; If not fall through to process.
- MOV BYTE PTR NUMBER_BUFFER,2 ;Store the previous 2.
- DO_PARAMETER: MOV ANSI_STATE,OFFSET PARAM_STATE ;Parameter state.
-
- ;------------------------------------------------;
-
- PARAM_STATE: CALL CK_QUOTE ;Is it single or double quotes?
- JZ STORE_STATE ;If yes, store string state.
- CMP AL,";" ;Is it semi-colon delimiter?
- JNZ CK_NUMBER ;If no, check if number.
- INC NUMBER_COUNT ;Else, increment number count.
- JMP SHORT BUFFER_CHAR ;Buffer the semi-colon.
-
- CK_NUMBER: CMP AL,"0" ;Is it below 0 ?
- JB FLUSH_BUFFER ;If yes, illegal; flush buffer.
- CMP AL,"9" ;Else, is it above 9 ?
- JA DO_COMMAND ;If yes, check for command char.
- CALL ACCUMULATE ;Else it's a number; accumulate.
- JMP SHORT BUFFER_CHAR ;Buffer the character.
-
- DO_COMMAND: MOV DI,OFFSET COMMAND_TABLE ;Point to legal ANSI commands.
- MOV CX,COMMAND_LENGTH ;Number of commands.
- REPNZ SCASB ;Check for a match.
- JNZ FLUSH_BUFFER ;If no match, flush sequence.
- INC NUMBER_COUNT ;Else, increment for last number.
- MOV DI,OFFSET COMMAND_END ;Point to appropriate command
- SHL CX,1 ; processing procedure.
- SUB DI,CX
- EXECUTE: CALL GET_BIOS_DATA ;Get cursor position data.
- CALL DS:[DI] ;Do command subroutine.
- JMP SHORT FLUSH_END ;Clear buffer.
-
- ;------------------------------------------------;
-
- QUOTE_STATE: CMP AL,QUOTE_TYPE ;Is it an ending string quote?
- JNZ BUFFER_CHAR ;If no, buffer literal.
- MOV BX,OFFSET PARAM_STATE ;Else, back to parameter parsing.
-
- ;------------------------------------------------;
-
- STORE_STATE: MOV ANSI_STATE,BX ;Store the ANSI state.
-
- ;------------------------------------------------;
-
- BUFFER_CHAR: MOV DI,ESC_COUNT ;Buffer the character in case
- CMP DI,ESC_BUFFER_SIZE ; ending ANSI command is illegal.
- JZ FLUSH_BUFFER ;If buffer full, flush.
- ADD DI,OFFSET ESC_BUFFER ;Point to next buffer position.
- STOSB ;Store the character.
- INC ESC_COUNT ;Increment the sequence count.
- RET
-
- ;------------------------------------------------;
-
- FLUSH_BUFFER: ;$
- if PCB ;$
- CALL BUFFER_CHAR ;@ Buffer current character also!
- FLUSH_BUFF2: ;@
- else ;$
- PUSH AX ;Save the current character. Might need removal
- endif ;$
- MOV SI,OFFSET ESC_BUFFER ;Point to the sequence buffer.
- MOV CX,ESC_COUNT ;Count of buffered characters.
- NEXT_FLUSH: LODSB ;Retrieve one.
- PUSH CX ;Save counter and pointer.
- PUSH SI
- CALL WRITE_CHAR ;Write character to screen.
- POP SI ;Restore counter and pointer.
- POP CX
- LOOP NEXT_FLUSH ;Flush entire buffer.
- ife PCB ;$
- POP AX ;@Retrieve last character. Might need removal
- CALL WRITE_CHAR ;@Write it also. Might need removal
- endif ;$
- FLUSH_END: MOV ESC_COUNT,0 ;Reset counter.
- MOV ANSI_STATE,OFFSET ESC_STATE ;Back to Esc state.
- MOV NUMBER_COUNT,0 ;Reset parameter counter.
- PUSH CS ;Point to our data.
- POP ES
- MOV DI,OFFSET NUMBER_BUFFER ;Clear number buffer
- MOV CX,ESC_BUFFER_SIZE / 2 ; to zeros.
- XOR AX,AX
- REP STOSW
- RET
- if PCB ;$
- ;------------------------------------------------;@
- COLOR_STATE: MOV AH,AL ;^ Save character
- CMP AL,"0" ;@ Is it below 0 ?
- JB FLUSH_BUFFER ;@ If yes, illegal; flush buffer.
- CMP AL,"9" ;@ Else, is it 0 - 9 ?
- JBE DO_COLOR ;@ If yes, Make color.
- CMP AL,'A' ;@ Is it below A ?
- JB FLUSH_BUFFER ;@ If yes, illegal; flush buffer.
- CMP AL,'F' ;@ Is it Above F ?
- JA FLUSH_BUFFER ;@ If yes, illegal; flush buffer.
- SUB AL,7 ;@ Else, adjust for Hex
- DO_COLOR: CALL ACCUM_COLOR ;@ Accumulate Color.
- MOV AH,AL ;^ get saved character
- INC NUMBER_COUNT ;@ Count the character
- CMP NUMBER_COUNT,2 ;@ Already got two?
- BUFFER_JUMP: JNE SHORT BUFFER_CHAR ;&;@ No, Buffer the character.
- TEST STATUS,OFF ;@ Else, is ANSI OFF ?
- JNZ FLUSH_BUFFER ;@ If yes, flush Esc, bracket.
- TEST STATUS,XOFF ;^ Are @Xnn colors off?
- JNZ FLUSH_END ;^ Yes, Ignore this completely
- INC CL ;& Is it @XFF restore code?
- JNZ COLOR_2 ;& No, Check for save code
- MOV CL,SAVE_ATTRIBUTE ;& Yes, Get back saved attribute
- JMP SHORT COLOR_3 ;& and set it
- COLOR_2: DEC CL ;& Is it @X00 save code
- JNZ COLOR_3 ;& No, just set it then
- MOV CL,ATTRIBUTE ;& Yes, Save the attribute
- MOV SAVE_ATTRIBUTE,CL ;&
- JMP FLUSH_END ;& and flush it
- COLOR_3: MOV ATTRIBUTE,CL ;@ Set Attribute
- JMP FLUSH_END ;@ Clear Buffer
-
- ;------------------------------------------------;@
- VARIABLE_SUB: CMP AL,'@' ;@ Is it another @
- JB SHORT_FLUSH ;@ No, and not valid, so flush
- JNZ BUFFER_JUMP ;&;@ No, Buffer the Char (indirect)
- MOV DX,OFFSET AT_VARIABLE_TABLE ;@ Point to Variable List
- XOR BX,BX ;@ Position in Variable List
- NEXT_VARI: MOV DI,DX ;@ Load DI
- INC BX ;@ Count the Variable
- MOV SI,OFFSET ESC_BUFFER ;@ Point to our Variable
- MOV CX,OFFSET LAST_VARIABLE ;@ Point to End of list
- SUB CX,DI ;@ Minus our current location
- MOV AL,'@' ;@ We need to start on these
- REPNE SCASB ;@ so find one
- JCXZ SHORT_FLUSH ;@ End of List? Yes
- MOV DX,DI ;@ No,Save Variable list pointer
- DEC DI ;@ No, Back up to the @
- MOV CX,ESC_COUNT ;@ Length of Variable
- REP CMPSB ;@ See if this one matches?
- JNZ NEXT_VARI ;@ Didn't match that one!
- CMP [DI],AL ;@ Last Character has to be an @
- JNZ NEXT_VARI ;@ Nope
- DEC BX ;@ Back up 1
- CMP BX,11 ;@ Is it an Action code
- JA NOT_ACTION ;@ No
- SHL BX,1 ;@ BX x 2 for proper offset
- MOV DI,OFFSET JUMP_TABLE ;@ Point to command table
- ADD DI,BX ;@ Adjust to the desired command
- JMP EXECUTE ;@ Execute the command
- NOT_ACTION: MOV SI, OFFSET SUB_TABLE ;@ Point to Sub Table
- MOV AX,BX ;@ Save Variable Number
- MOV CX,BX ;@ Copy Variable Number
- XOR BX,BX ;@ Zero Offset
- XOR DX,DX ;@ Zero out initial length
- SUB CX,11 ;@ Adjust Variable Number
- NEXT_OFFSET: ADD BX,DX ;@ Add last Length to Offset
- MOV DL,[SI] ;@ Get Length
- INC SI ;@ Bump the pointer
- LOOP NEXT_OFFSET ;@ Do all of them
- MOV CX,DX ;@ Get last Length
- MOV SI,OFFSET SUB_LIST ;@ Point to the substitue buffer.
- ADD SI,BX ;@ Add Offset
- SUB AX,34 ;@ Is It a String Variable
- JB IS_STRING ;@ Yes, Flush our Substitute
- CMP AX,1 ;@ Is it Date ot Time?
- JBE IS_TIMEDATE ;@ No, It's a Number
- SUB AX,2 ;@ Adjust Variable number
- CALL NUMBER_PARSE ;@ Create a Numeric value then
- JMP SHORT VAR_END ;@ Flush our Number
- IS_TIMEDATE: CALL MAKE_TIMEDATE ;@
- IS_STRING: MOV DI,SI ;@ Copy Pointer to DI for SCASB
- MOV AL,0 ;@ We look for a Zero
- REPNE SCASB ;@ Findit it
- JNE GOT_END ;@ Skip if we didn't hit a Zero
- DEC DI ;@ Back up if we did
- GOT_END: MOV CX,DI ;@ Get Current Location
- SUB CX,SI ;@ Subtract Starting Location
- VAR_END: JMP NEXT_FLUSH ;@ Flush our Substitute
-
- SHORT_FLUSH: PUSH AX ;& Save Character
- CALL FLUSH_BUFF2 ;@ Flush what we have now
- POP AX ;& Restore Character
- JMP ESC_STATE ;& And save the new state
-
- ;------------------------------------------------;@
- ATX_STATE: MOV BX,OFFSET COLOR_STATE ;@ Assume 'X' Character
- CMP AL,"X" ;@ Is it X? If yes, store
- JZ SHORT_STORE ;@ char. and next state.
- CMP AL,'@' ;@ Is it another '@' already?
- JZ WRITE_CHAR ;@ Yes!
- CMP AL,ESC_CHAR ;& Is it an Escape
- JE SHORT_FLUSH ;& Yes, so flush buffer & restart
- MOV BX,OFFSET VARIABLE_SUB ;@ No, Must be a Variable
- SHORT_STORE: JMP STORE_STATE ;@ Store the state
- endif ;$
- ;------------------------------------------------;
- ; Slow video writes are via BIOS Write TTY. ;
- ;------------------------------------------------;
-
- WRITE_CHAR: CMP AL,BELL ;Let BIOS process BS and BELL.
- JZ WRITE_TTY
- CMP AL,BS
- JZ WRITE_TTY
-
- CALL GET_BIOS_DATA ;Get BIOS video data.
- CMP AL,TAB ;Is character a TAB?
- JNZ CK_ACTIVE ;If no, process normally.
- MOV CX,CURSOR_POSN ;Else, expand TAB to
- AND CX,7 ; appropriate space characters.
- NEG CX
- ADD CX,8
- NEXT_TAB: PUSH CX
- MOV AL,SPACE
- CALL CK_ACTIVE
- POP CX
- LOOP NEXT_TAB
- RET
-
- CK_ACTIVE: TEST STATUS,OFF ;Is ANSI OFF?
- JNZ WRITE_TTY ;If yes, write via BIOS TTY.
- CK_FAST: CALL CK_SLOW_TEXT ;Is ANSI SLOW or in graphics
- JNC WRITE_FAST ; mode? If no, write fast.
-
- CMP AL,CR ;Let BIOS handle CR and LF.
- JZ WRITE_TTY
- CMP AL,LF
- JZ WRITE_TTY
-
- WRITE_SLOW: PUSH AX ;Else, write character/attribute
- MOV CX,1 ; at current cursor position
- MOV BH,ACTIVE_PAGE ; via BIOS.
- MOV BL,ATTRIBUTE
- MOV AH,9
- INT 10H
- POP AX
-
- CMP LINE_WRAP,ON ;Is line wrap on?
- JZ TTY ;If yes, continue.
- MOV CX,CRT_COLS ;Else, cursor at rightmost
- DEC CL ; column?
- CMP CL,CURSOR_COL ;If yes, continue, else
- JNZ TTY ; return without writing.
- RET
-
- ;------------------------------------------------;
-
- WRITE_TTY: MOV BL,7 ;Attribute in graphics mode.
- TTY: MOV AH,0EH
- INT 10H
- RET
-
- ;----------------------------------------------------------------------------;
- ; Fast screen writes are directly to the video buffer without retrace check. ;
- ;----------------------------------------------------------------------------;
-
- WRITE_FAST: PUSH ES ;Preserve extra segment.
- MOV DX,CURSOR_POSN ;Retrieve cursor position.
- CMP AL,CR ;Carriage return?
- JNZ CK_LINEFEED ;If no, check linefeed.
- XOR DL,DL ;Else, cursor to first column.
- JMP SHORT UPDATE_CURSOR
- CK_LINEFEED: CALL VIDEO_SETUP ;Calculate video address.
- CMP AL,LF ;Linefeed?
- JZ NEXT_ROW ;If yes, next row.
-
- MOV AH,ATTRIBUTE ;Retrieve attribute.
- STOSW ;Put char/attrib in video buffer.
- INC DL ;Increment cursor column.
- CMP DL,BYTE PTR CRT_COLS ;End of row?
- JB UPDATE_CURSOR ;If no, update cursor.
-
- CMP LINE_WRAP,OFF ;Else, line wrap off?
- JZ FAST_END ;If yes, don't move cursor.
- XOR DL,DL ;Else, column zero.
- NEXT_ROW: INC DH ;Next row.
- CALL INFORMATION ;Get displayable row info.
- CMP DH,AL ;Beyond the bottom of screen?
- JBE UPDATE_CURSOR ;If no, update cursor.
-
- DEC DH ;Else, cursor to original row.
- MOV AX,CRT_COLS ;. Get number of columns
- PUSH DX ;. Save Cursor position
- PUSH AX ;. Save Columns
- SHL AX,1 ;. Twice for Char/Attribute
- MOV SI,AX ;. Starting offset in SI
- MOV DL,START_SCROLL ;. Where we allow scroll to start
- MUL DL ;. Calculate offset in AX
- SUB DH,DL ;. Reduce line count
- MOV DI,CRT_START ;Point destination to top.
- ADD DI,AX ;. Add offset
- ADD SI,DI ;. Point source to second row
- POP AX ;. Get Back Columns
- PUSH AX ;. Save it again
- MUL DH ;Times displayable rows - 1.
- MOV CX,AX ; equals char/attrib to scroll.
- PUSH DS ;Save data segment and
- PUSH ES ; point to video segment.
- POP DS
- REP MOVSW ;Scroll the screen.
- POP DS ;Restore data segment.
- POP CX ;Retrieve CRT columns.
- POP DX ;.Get back Cursor info
- MOV AL,SPACE ;Write space/attrib to
- MOV AH,ATTRIBUTE ; bottom row.
- REP STOSW
-
- UPDATE_CURSOR: CALL SET_CURSOR ;Update the cursor position.
- FAST_END: POP ES ;Restore extra segment.
- RET
- if PCB ;$
- ;@************ SUPPORT ROUTINES *************;
-
- QOFF: MOV AL,0FFH ;& Show QOFF
- JMP SHORT QON2 ;&
- QON: XOR AL,AL ;& Show QON
- QON2: MOV Q_STATE,AL ;& Store the state
- RET ;& All done
-
- BEEP: MOV AL,7 ;@
- JMP WRITE_CHAR ;@
- MORE: MOV AX,MORE_DELAY ;@
- JMP SHORT PAUSE2 ;@
- PAUSE: MOV AX,PAUSE_DELAY ;@
- PAUSE2: CMP Q_STATE,0 ;& Are we at a QOFF state
- JNZ WAIT1 ;& Yes, then these are WAITs
- MOV SI,OFFSET MORE_PROMPT ;@ Point to More? Prompt
- MOV CX,MORE_LENGTH ;@ Get the Length of it
- JMP SHORT WAIT2 ;@ Go Wait
- WAIT1: MOV AX,WAIT_DELAY ;@
- MOV SI,OFFSET WAIT_PROMPT ;@ Point to Wait Prompt
- MOV CX,WAIT_LENGTH ;@ Get the Length of it
- WAIT2: MOV PAUSE_TIMER,AX ;@
- ; PUSH CX ;@ Save Length
- WAIT2_LOOP: LODSB ;@ Get Character
- PUSH CX ;@
- PUSH SI ;@
- CALL WRITE_CHAR ;@ Output it
- POP SI ;@
- POP CX ;@
- LOOP WAIT2_LOOP ;@ Do all the Characters
- WAIT_LOOP: MOV AH,1 ;@ KeyBoard Status
- INT 16H ;@ Keyboard I/O Services
- JNZ CONTINUE ;@ Key Hit!
- CMP PAUSE_TIMER,0 ;@ Timer Run out?
- JNE WAIT_LOOP ;@ No
- JMP SHORT WAIT3 ;@ Yes
- CONTINUE: MOV AH,0 ;@ KeyBoard Read
- INT 16H ;@ Keyboard I/O Services
- WAIT3: ;@
- XOR CL,CL ;@ Clear the Attribute
- XCHG CL,ATTRIBUTE ;& and
- PUSH CX ;& save it too
- MOV DX,CURSOR_POSN ;& Get Cursor
- MOV DL,0 ;& First column
- CALL SET_CURSOR ;& Set the new Cursor
- CALL ERASE_2 ;& Erase the line
- ;&
- ;& The following lines (and the PUSH CX above) will clear only the PROMPT
- ;& and leave the cursor where it was when the prompt appears. This was
- ;& different than PCBoard 14.5 so I changed it to clear the entire line
- ;& via the above four lines. Left the old code in case someome wanted it.
- ;&
- ;& POP CX ;@ Get back Length
- ;&ERASE_LOOP: PUSH CX ;@ Save it again
- ;& MOV AL,BS ;@ Send BS
- ;& CALL WRITE_CHAR ;@ character
- ;& MOV AL,' ' ;@ and then space
- ;& CALL WRITE_CHAR ;@ character to erase
- ;& MOV AL,BS ;@ then BS again
- ;& CALL WRITE_CHAR ;@ to backup.
- ;& POP CX ;@ get back length again
- ;& LOOP ERASE_LOOP ;@ Erase entire prompt.
- POP CX ;& Restore
- MOV ATTRIBUTE,CL ;& the Attribute
- RET ;@
- AUTOOFF: MOV AX,WAIT_DELAY ;@ Restore More to a Wait
- JMP SHORT AUTO2 ;@
- AUTOMORE: MOV AX,PAUSE_DELAY ;@ Make More a Pause
- AUTO2: MOV MORE_DELAY,AX ;@
- SKIP_IT: RET ;@
- endif ;$
- ;************* SUPPORT ROUTINES *************;
-
- CK_QUOTE: MOV BX,OFFSET QUOTE_STATE ;Assume quote state.
- MOV AH,DOUBLE_QUOTE
- CMP AL,AH ;Is it double quote?
- JZ GOT_QUOTE ;If yes, string delimiter.
- MOV AH,SINGLE_QUOTE ;Is it single quote?
- CMP AL,AH ;Is yes, string delimiter.
- JNZ QUOTE_END ;Else, return ZR = 0.
- GOT_QUOTE: MOV QUOTE_TYPE,AH ;Store as matching string end.
- QUOTE_END: RET
-
- ;------------------------------------------------;
-
- ACCUMULATE: PUSH AX ;Preserve number character.
- SUB AL,"0" ;Convert ASCII to binary.
- MOV CL,AL ;Save the number.
- MOV AX,10 ;Multiply previous count by 10.
- MOV BX,NUMBER_COUNT
- MUL BYTE PTR NUMBER_BUFFER[BX]
- ADD AL,CL ;Add in new number
- MOV BYTE PTR NUMBER_BUFFER[BX],AL ; and store.
- POP AX
- RET
- if PCB ;$
- ;------------------------------------------------;@
-
- ACCUM_COLOR: PUSH AX ;@ Preserve number character.
- SUB AL,"0" ;@ Convert ASCII to hex
- MOV AH,BYTE PTR NUMBER_BUFFER ;@ Get current number
- SHL AH,1 ;@ Shift left 4 bits
- SHL AH,1 ;@
- SHL AH,1 ;@
- SHL AH,1 ;@
- OR AH,AL ;@ Add in new number
- MOV BYTE PTR NUMBER_BUFFER,AH ;@ and store.
- MOV CL,AH ;@ Return with Color in CL
- POP AX ;@
- RET ;@
-
- NUMBER_PARSE: MOV BX,[SI] ;@ Get low word
- MOV DX,AX ;@ Save Variable Number
- XOR AX,AX ;@ Assume Integer
- CMP CX,4 ;@ Is that a Long Integer?
- JNE SHORT_INT ;@ No, Integer
- MOV AX,[SI + 2] ;@ Yes, Get high word
- SHORT_INT: MOV DI, OFFSET PARSE_BUFFER ;@ Point DI at number space
- MOV CX,10 ;@ Set divisor to 10
- XOR SI,SI ;@ Clear SI as counter
- MOV COMMA,2 ;@ Assume a Ratio
- CMP DX,2 ;@ Is it a Ratio?
- JB GETDIGIT ;@ No
- RESET_COMMA: MOV COMMA,4 ;@ Set Comma Counter
- GETDIGIT: DEC DI ;@ Point DI at correct character
- INC SI ;@ Register that we have a character
- DEC COMMA ;@ Do we need a Comma?
- JNZ NO_COMMA ;@ No
- MOV BYTE PTR [DI],',' ;@ Yes, So Put one in!
- JMP RESET_COMMA ;@ And restart the Comma count.
- NO_COMMA: XOR DX,DX ;@ Clear DX to take remainder
- DIV CX ;@ Divide AX first (High word)
- MOV BP,AX ;@ Save quotient
- MOV AX,BX ;@ Get low word
- DIV CX ;@ DX had leftover from first divide
- MOV BX,AX ;@ Save quotient
- MOV AX,BP ;@ Put high word back
- ADD DL,30h ;@ Make it an ASCII digit from remainder
- MOV [DI],DL ;@ Put it in our string
- OR AX,AX ;@ Is high word zero?
- JNZ GETDIGIT ;@ No keep going
- OR BX,BX ;@ Is low word zero?
- JNZ GETDIGIT ;@ No keep going
- MOV CX,SI ;@ Digit count to CX
- MOV SI,DI ;@ String Pointer to SI
- MOV DI, OFFSET PARSE_BUFFER ;@ Point DI at number space
- CMP BYTE PTR [DI][-2],',' ;@ Was it a Ratio
- JNE NOT_RATIO ;@ No, nevermind
- MOV BYTE PTR [DI][-2],'.' ;@ Change comma to Decimal
- MOV BYTE PTR [DI],":" ;@ Yes, Add ':1' to it
- MOV BYTE PTR [DI][1],"1" ;@
- ADD CX,2 ;@ Account for two more characers
- NOT_RATIO: RET ;@
-
- MAKE_TIMEDATE: MOV DI, OFFSET NUMBER_BUFFER ;@ Point to Number Buffer
- MOV SI,DI ;@ Save it in SI too
- JE MAKE_TIME ;@ It was TIME on Entry!
- MOV CX,8 ;@ It was DATE! Length = 8
- PUSH CX ;@ Save Length
- MOV AH,04H ;@ Get date service
- INT 1AH ;@ Call BIOS - return codes as follows:
- PUSH CX ;@ CH = Century (19-20) CL = Year (00-99)
- PUSH DX ;@ DH = Month (1-12) DL = Day (00-31)
- MOV AL,DH ;@ Month
- CALL ASCII ;@ Convert byte to ASCII digits
- MOV AL,'-' ;@
- STOSB ;@
- POP AX ;@ Day - was DX when pushed
- CALL ASCII ;@ Convert byte to ASCII digits
- MOV AL,'-' ;@
- STOSB ;@
- POP AX ;@ Year - was CX when pushed
- POP CX ;@ Restore Length
- JMP SHORT ASCII ;@ Convert byte to ASCII digit
-
- MAKE_TIME: MOV CX,5 ;@ Length = 5
- PUSH CX ;@ Save Length
- MOV AH,02H ;@ Get time service
- INT 1AH ;@ Call BIOS - return codes as follows:
- PUSH CX ;@ CH = Hours (0-23) CL = Minutes (0-59)
- MOV AL,CH ;@ Hours
- CALL ASCII ;@ Convert byte to ASCII digits
- MOV AL,':' ;@
- STOSB ;@
- POP AX ;@ Minutes - was CX when pushed
- POP CX ;@ Restore Length
- ASCII: MOV AH,AL ;@ Need to get BCD Digits
- SHR AL,1 ;@ MSD in AL
- SHR AL,1 ;@ lower
- SHR AL,1 ;@ 4
- SHR AL,1 ;@ Bits
- AND AH,0FH ;@ And LSD in AH cleanly
- OR AX,3030H ;@ Convert to ASCII
- STOSW ;@ Stuff Digits into Buffer (in reverse)
- RET ;@ SI Points to String Data
- endif ;$
- ;---------------------------------------------------------------------------;
- ; OUTPUT: CY = 1 if write SLOW mode or in graphics mode; CY = 0 otherwise. ;
- ;---------------------------------------------------------------------------;
-
- CK_SLOW_TEXT: TEST STATUS,SLOW
- JNZ SLOW_MODE
- CMP CRT_MODE,7
- JZ TEXT_MODE
- CMP CRT_MODE,3
- JA SLOW_MODE
- TEXT_MODE: CLC
- RET
-
- SLOW_MODE: STC
- RET
-
- ;-------------------------------------;
- ; OUTPUT: AL = Screen rows minus one ;
- ;-------------------------------------;
-
- INFORMATION: PUSH DS ;Save data segment.
- MOV AX,40H ;Point to BIOS data.
- MOV DS,AX
- MOV AL,DS:[84H] ;Retrieve rows - 1.
- OR AL,AL ;BIOS supported?
- JNZ INFO_END ;If yes, done here.
- MOV AL,24 ;Else, assume 25 lines.
- INFO_END: POP DS
- RET
-
- ;------------------------------------------------------------------------------;
- ; INPUT: DX = Cursor position. ;
- ; OUTPUT: ES = Video buffer segment; DI = Video buffer offset; AX,DX preserved ;
- ;------------------------------------------------------------------------------;
-
- VIDEO_SETUP: PUSH AX
- MOV AX,CRT_COLS ;Retrieve CRT columns.
- MUL DH ;Times cursor row.
- MOV BL,DL
- XOR BH,BH
- ADD AX,BX ;Plus cursor column.
- SHL AX,1 ;Times two for attribute.
- MOV DI,CRT_START ;Plus starting video offset.
- ADD DI,AX ;Equals destination.
-
- MOV BX,0B000H ;Assume mono card.
- CMP ADDR_6845,3B4H ;Is it mono port?
- JZ VIDEO_SEGMENT ;If yes, guessed right.
- ADD BX,800H ;Else, point to color segment.
- VIDEO_SEGMENT: MOV ES,BX
- POP AX
- RET
-
- ;------------------------------------------------;
- ; Move BIOS video data into our data segment. ;
- ;------------------------------------------------;
-
- GET_BIOS_DATA: PUSH DS
- PUSH DI ;Point to BIOS data segment.
- MOV BX,40H
- MOV DS,BX
- MOV SI,BIOS_ACTIVE_PAGE ;Start with active page.
- MOV DI,OFFSET ACTIVE_PAGE
- MOVSB ;Retrieve active page
- MOVSW ; and address of 6845 port.
- MOV SI,BIOS_CRT_MODE ;Retrieve CRT mode, CRT columns,
- MOV CX,CRT_DATA_LENGTH ; CRT length, CRT start.
- REP MOVSB
- MOV BL,ES:ACTIVE_PAGE ;Use active page as index
- XOR BH,BH ; of active cursor position.
- SHL BX,1
- ADD SI,BX
- MOVSW
- POP DI
- POP DS
- RET
-
- ;----------------------------------------------------------------------------;
- ; OUTPUT: BL = First parameter; BH = Second parameter; DX = cursor position. ;
- ;----------------------------------------------------------------------------;
-
- ADJUST_NUMBER: MOV BX,WORD PTR NUMBER_BUFFER
- OR BH,BH
- JNZ ADJUST_AL ;If either parameter zero,
- INC BH ; increment to convert
- ADJUST_AL: OR BL,BL ; to base one.
- JNZ ADJUST_END
- INC BL
- ADJUST_END: MOV DX,CURSOR_POSN ;Return cursor position.
- RET
-
- ;--------------------------------------------------------------------------;
- ; INPUT: AX = number; BP = 0 if console output; BP = 1 if storage output. ;
- ;--------------------------------------------------------------------------;
-
- DECIMAL_OUT: MOV BX,10 ;Divisor of ten.
- XOR CX,CX ;Zero in counter.
- NEXT_COUNT: XOR DX,DX ;Zero in high half.
- DIV BX ;Divide by ten.
- ADD DL,"0" ;Convert to ASCII.
- PUSH DX ;Save results.
- INC CX ;Also increment count.
- CMP AX,0 ;Are we done?
- JNZ NEXT_COUNT ;Continue until zero.
- OR BP,BP ;If BP zero, output to screen.
- JNZ DEVICE_OUTPUT ;Else, store in buffer.
-
- REPORT_OUTPUT: POP AX ;Retrieve number.
- CALL PRINT_CHAR ;Display it.
- LOOP REPORT_OUTPUT
- RET
-
- DEVICE_OUTPUT: CMP CX,2 ;Two digits?
- JZ TWO_DIGITS ;If yes, process normally.
- MOV AL,"0" ;Else, store leading zero.
- STOSB
-
- TWO_DIGITS: POP AX ;Retrieve number.
- STOSB ;Store it
- LOOP TWO_DIGITS
- RET
-
- ;************* ANSI COMMAND SUBSET *************;
-
- CLS: MOV BH,7 ;Assume normal attribute.
- MOV BL,BYTE PTR CRT_MODE ;Get current video mode.
- CMP BL,4
- JBE CK_CLS_STATUS ;If text mode then check if
- CMP BL,7 ; ANSI active.
- JZ CK_CLS_STATUS
- XOR BH,BH ;Else, use black attribute
- TEST STATUS,OFF
- JNZ CLS_SLOW ;If ANSI inactive, via BIOS.
- JMP SHORT CK_CLS_SLOW ;Else, check if FAST or SLOW.
-
- CK_CLS_STATUS: TEST STATUS,OFF ;Is ANSI OFF?
- JNZ CLS_SLOW ;If yes, CLS via BIOS.
- MOV BH,ATTRIBUTE ;Else, current attribute.
- CK_CLS_SLOW: CALL CK_SLOW_TEXT
- JC CLS_SLOW ;If ANSI SLOW, via BIOS.
-
- CLS_FAST: MOV AH,BH ;Else, attribute in high half.
- MOV AL,SPACE ;Space character in low half.
- XOR DX,DX ;Cursor position home.
- MOV DH,START_SCROLL ;$ protect lines
- CALL VIDEO_SETUP ;Calculate video address.
- MOV CX,CRT_LEN ;Retrieve CRT length.
- SHR CX,1 ;Times two for attribute.
- REP STOSW ;Write directly to video buffer.
- JMP SHORT SET_CURSOR ;Set the cursor top left corner.
-
- CLS_SLOW: CALL INFORMATION ;Get displayable rows.
- MOV DH,AL ;Store in DH.
- MOV DL,BYTE PTR CRT_COLS ;Retrieve CRT columns.
- DEC DL ;Adjust to zero base.
- XOR CX,CX ;Scroll active page.
- MOV AX,600H
- INT 10H
- XOR DX,DX ;Home the cursor.
- JMP SHORT SET_CURSOR
-
- ;------------------------------------------------;
- CURS_POSITION: ;These two commands are the same.
- HORZ_VERT_POS: CALL INFORMATION ;Returns AL = screen rows.
- CALL ADJUST_NUMBER ;Returns BL,BH = parameters.
- SUB BX,101H ;Zero based.
- CMP BL,AL ;If cursor request within
- ;$ JA CURSOR_END ; boundaries of screen, set it.
- JBE ROWOK ;$boundaries of screen, set it.
- MOV BL,AL ;$Set to last row
- ROWOK: CMP BH,BYTE PTR CRT_COLS ;$
- ;$ JAE CURSOR_END
- JB COLOK ;$
- MOV BH,BYTE PTR CRT_COLS ;$Set to
- DEC BH ;$ last column
- COLOK: XCHG BH,BL ;
- MOV DX,BX
-
- SET_CURSOR: MOV BH,ACTIVE_PAGE ;Set cursor via BIOS.
- MOV AH,2
- INT 10H
- CURSOR_END: RET
-
- ;------------------------------------------------;
-
- CURSOR_UP: CALL ADJUST_NUMBER ;Move cursor up one or more rows
- OR DH,DH ; without changing column.
- JZ CURSOR_END ;If already at top, ignore.
- SUB DH,BL
- JNC SET_CURSOR ;Stay in bounds.
- XOR DH,DH
- JMP SHORT SET_CURSOR
-
- ;------------------------------------------------;
-
- CURSOR_DOWN: CALL INFORMATION ;Returns AL = screen rows.
- CALL ADJUST_NUMBER ;Returns BL,BH =nos.; DX = cursor
- CMP DH,AL ;Move cursor down requested
- JZ CURSOR_END ; rows without changing column.
- ADD DH,BL
- CMP DH,AL
- JNA SET_CURSOR
- MOV DH,AL ;Stay in bounds.
- JMP SHORT SET_CURSOR
-
- ;------------------------------------------------;
-
- CURS_FORWARD: CALL ADJUST_NUMBER ;Returns BL,BH =nos.; DX = cursor
- MOV BH,BYTE PTR CRT_COLS ;Retrieve displayable columns.
- DEC BH ;Adjust to zero base.
- CMP DL,BH ;Move cursor forward one or more
- JZ CURSOR_END ; columns without changing row.
- ADD DL,BL
- CMP DL,BH
- JNA SET_CURSOR
- MOV DL,BH ;Stay in bounds.
- JMP SHORT SET_CURSOR
-
- ;------------------------------------------------;
-
- CURS_BACKWARD: CALL ADJUST_NUMBER ;Returns BL,BH =nos.; DX = cursor
- OR DL,DL ;Move cursor backward one or
- JZ CURSOR_END ; more columns without changing
- SUB DL,BL ; row. Ignore if already left.
- JNC SET_CURSOR
- XOR DL,DL ;Stay in bounds.
- JMP SHORT SET_CURSOR
-
- ;--------------------------------------------------------;
- ; Report cursor position via console; Format: ESC[#;#R ;
- ;--------------------------------------------------------;
-
- DEVICE_STATUS: MOV DI,OFFSET DEVICE_STATUS_BUFFER
- MOV AL,ESC_CHAR
- STOSB ;Store leading Esc, bracket
- MOV AL,"[" ;in special Device Status Buffer.
- STOSB
-
- MOV AL,CURSOR_ROW ;Retrieve cursor row.
- XOR AH,AH ;Zero in high half.
- INC AX ;Convert to base one.
- MOV BP,1 ;Flag as storage.
- CALL DECIMAL_OUT ;Convert to ASCII.
- MOV AL,";" ;Store delimiting semi-colon.
- STOSB
- MOV AL,CURSOR_COL ;Do same with cursor column.
- XOR AH,AH
- INC AX
- CALL DECIMAL_OUT
- MOV AL,"R" ;Add command character
- STOSB
- MOV AL,CR ; and carriage return.
- STOSB
- SUB DI,OFFSET DEVICE_STATUS_BUFFER ;Setup for console out.
- MOV REASSIGN_COUNT,DI
- MOV REASSIGN_POS,OFFSET DEVICE_STATUS_BUFFER
- MOV REASSIGN_FLAG,ON
- MOV REMOVE_FLAG,OFF
- RET
-
- ;------------------------------------------------;
-
- SAVE_CURSOR: MOV DX,CURSOR_POSN
- MOV SAVE_POSITION,DX
- RET
-
- ;------------------------------------------------;
-
- RESTORE_CURS: MOV DX,SAVE_POSITION
- JMP SET_CURSOR
-
- ;------------------------------------------------;
-
- ERASE_IN_LINE: MOV DX,CURSOR_POSN ;Erase from the cursor to
- ERASE_2: MOV CX,CRT_COLS ;& the end of the line, including
- SUB CL,DL ; the current cursor position.
- CALL CK_SLOW_TEXT
- JC ERASE_SLOW ;If ANSI ON and not graphics,
- CALL VIDEO_SETUP ; write directly to video buffer
- MOV AL,SPACE ; with space/attribute.
- MOV AH,ATTRIBUTE
- REP STOSW
- RET
-
- ERASE_SLOW: MOV CX,DX ;Else, erase SLOW via
- MOV DL,BYTE PTR CRT_COLS ; BIOS scroll active page.
- DEC DL
- MOV BH,ATTRIBUTE
- MOV AX,601H
- INT 10H
- RET
-
- ;------------------------------------------------;
- ; Set Graphics Rendition ;
- ;------------------------------------------------;
-
- SGR: MOV SI,OFFSET NUMBER_BUFFER ;Point to number parameters.
- NEXT_SGR: LODSB ;Retrieve parameter.
- MOV DI,OFFSET ATTRIBUTE_TABLE ;Look up attribute in
- MOV CX,ATTRIBUTE_LENGTH ; translation table.
- REPNZ SCASB
- JNZ SGR_LOOP
-
- MOV DI,OFFSET ATTRIBUTE_END
- SHL CX,1
- SUB DI,CX
- MOV AX,[DI]
- AND ATTRIBUTE,AL ;If match, AND with strip mask.
- OR ATTRIBUTE,AH ;OR with add mask.
- SGR_LOOP: DEC NUMBER_COUNT ;Do all parameters.
- JNZ NEXT_SGR
- RET
-
- ;------------------------------------------------;
-
- SET_MODE: MOV AH,ON ;Assume command 7,
- JMP SHORT CK_WRAP ; turn line wrap on.
-
- ;------------------------------------------------;
-
- RESET_MODE: MOV AH,OFF ;Assume turn line wrap off.
- CK_WRAP: MOV AL,BYTE PTR NUMBER_BUFFER ;Retrieve number parameter.
- CMP AL,7 ;Is it 7?
- JZ SET_WRAP ;If yes, set wrap mode.
- JB DO_MODE ;1 - 6 valid modes.
- CMP AL,14 ;14 - 16 valid modes.
- JB MODE_END
- CMP AL,19
- JA MODE_END ;If above 16, illegal.
- DO_MODE: XOR AH,AH ;Else, set video mode
- INT 10H ; to parameter.
- RET
-
- SET_WRAP: MOV LINE_WRAP,AH
- MODE_END: RET
-
- ;--------------------------------------------------------------------;
- ; Keyboard Key Reassignment: First convert ASCII numbers to binary, ;
- ; parse out delimiting semi-colons, and quote string delimiters. ;
- ;--------------------------------------------------------------------;
-
- REASSIGNMENT: TEST STATUS,POFF ;:If assignment are OFF,
- JZ NOT_POFF ;: then exit as if
- JMP ASSIGN_FLUSH ;: we are out of room.
- NOT_POFF: ;:
- MOV CX,ESC_COUNT ;Retrieve length of Esc sequence.
- DEC CX ;Adjust.
- MOV SI,OFFSET ESC_BUFFER + 2 ;Point past Esc, bracket.
- MOV DI,OFFSET PARSE_BUFFER ;Point to parse storage.
- NEXT_STRING: MOV QUOTE_TYPE,0 ;Reset quote type.
- NEXT_NUM: XOR DL,DL ;Use DL to carry number; init = 0
- XOR BP,BP ;Use BP as number flag.
- NEXT_PARAM: LODSB ;Retrieve a byte.
- DEC CX ;Decrement string length counter.
- JZ PARSE_END ;If zero, done.
- MOV AH,QUOTE_TYPE ;Else, retrieve quote type.
- OR AH,AH ;If zero, not in string.
- JNZ QUOTE_MODE ;Else, go to string mode.
- CALL CK_QUOTE ;Is character a quote?
- JZ NEXT_PARAM ;If yes, ignore.
- CMP AL,";" ;Else, is it semi-colon?
- JZ STORE_NUMBER ;If yes, number delimiter.
-
- SUB AL,"0" ;Else, must be number; convert
- MOV DH,AL ; to binary; save in DH.
- MOV AX,10 ;Multiply current total by ten.
- MUL DL
- ADD AL,DH ;Add new number.
- MOV DL,AL ;Save in DL.
- MOV BP,1 ;Flag that number mode active.
- JMP SHORT NEXT_PARAM ;Next parameter.
-
- STORE_NUMBER: OR BP,BP ;If number mode flag not set then
- JZ NEXT_PARAM ;semi-colon not prefaced with no.
- MOV AL,DL ;Else, store number.
- STOSB
- JMP SHORT NEXT_NUM ;Reset number carrying registers.
-
- QUOTE_MODE: CMP AL,AH ;Is current char a string ending
- JZ NEXT_STRING ; quote? If yes, exit quote mode
- STOSB ;Else, store char as literal.
- JMP SHORT NEXT_PARAM
-
- ;----------------------------------------------------------------------------;
- ; Remove duplicate assignments if removal leaves room for new assignment. ;
- ; If no duplicate and room, add new assignment, else flush buffer to screen. ;
- ;----------------------------------------------------------------------------;
-
- PARSE_END: OR BP,BP ;Was last parameter a number?
- JZ CK_LENGTH ;If no, skip.
- MOV AL,DL ;Else, store the last number.
- STOSB
- CK_LENGTH: SUB DI,OFFSET PARSE_BUFFER - 2 ;Calculate string length
- MOV AX,DI ; including word for length.
- MOV BX,WORD PTR PARSE_BUFFER ;BL=new first ASCII; BH=2nd.
- MOV CX,4 ;String length has to be at
- OR BL,BL ;+least word + 2 for old = 4
- JZ CK_LEGAL ; for extended key reassignment.
- DEC CX ;And word + 1 for old = 3
- CK_LEGAL: CMP AX,CX ; for regular ASCII reassignment.
- JB ASSIGN_FLUSH ;If not, illegal; flush buffer.
- JNE DOCHK ;+If equal then unassign.
- XOR AX,AX ;+
- DOCHK: MOV BP,BUFFER_END ;BP to carry buffer end pointer.
- CALL CK_MATCH ;Is char already reassigned?
- JC CK_ROOM ;If no, check room for new.
-
- CK_REMOVE: MOV CX,DX ;REASSIGN_END - string end
- SUB CX,SI ; = bytes to move.
- JZ CK_ROOM ;If zero, last string.
- SUB DX,[DI] ;Is REASSIGN_END - old string
- ADD DX,AX ; + new string >
- CMP DX,BP ; BUFFER_END?
- JA ASSIGN_FLUSH ;If yes, flush buffer to screen.
- REP MOVSB ;Else, move them down in buffer.
- JMP SHORT STORE_NEW
-
- CK_ROOM: ADD DX,AX ;New string + current strings.
- CMP DX,BP ;Greater than buffer size?
- JA ASSIGN_FLUSH ;If yes, flush new string.
- STORE_NEW: MOV SI,OFFSET PARSE_BUFFER ;Else, room for new string.
- TEST AX,255 ;+Any reassign?
- JZ NOREASG ;+no reassignment
- STOSW ;Store string length first.
- MOV CX,AX ;Adjust counter.
- DEC CX
- DEC CX
- REP MOVSB ;Store the actual string.
- NOREASG: MOV REASSIGN_END,DI ;+Store new string end.
- RET
-
- ASSIGN_FLUSH: CMP AX,2 ;+Any key number?
- JNE FLUSHIN ;+no
- MOV AX,OFFSET REASSIGNMENT_BUFFER
- MOV REASSIGN_END,AX ;+flush all reassigns.
- RET ;+
- FLUSHIN: MOV AL,"p" ;+If buffer full, flush string
- JMP FLUSH_BUFFER ; including ending "p" command.
-
- ;------------------------------------------------------------------------------;
- ; INPUT: BL = first ASCII code to match; BH = extended if BL = 0 ;
- ; OUTPUT: CY = 1 if no match found; CY = 0 if match found. ;
- ; DI points to string length of match; DI+2 points to start of string. ;
- ; SI = end of string; DX = REASSIGN_END; BP = BUFFER_END ;
- ;------------------------------------------------------------------------------;
-
- CK_MATCH: MOV DX,REASSIGN_END ;Current strings end.
- MOV SI,OFFSET REASSIGNMENT_BUFFER ;Point to buffer.
- NEXT_MATCH: MOV DI,SI ;Current record.
- CMP DI,DX ;End of strings?
- JAE NO_MATCH ;If yes, no match.
- MOV CX,[DI+2] ;CL=current first ASCII; CH=2nd
- ADD SI,[DI] ;Point to next record.
- CMP BL,CL ;First characters match?
- JNZ NEXT_MATCH ;If no, check next record.
- OR BL,BL ;Extended code? ie zero.
- JNZ MATCH ;If no, then match.
- CMP BH,CH ;Else, check second code.
- JNZ NEXT_MATCH ;If not same, no match.
- MATCH: CLC ;Else return with CY = 0
- RET
-
- NO_MATCH: STC ;No match; CY = 1.
- RET
-
- ;----------------------------------------------------------------------;
- ; Buffer area will write over disposable data and initialization code. ;
- ;----------------------------------------------------------------------;
-
- ESC_BUFFER = $
- NUMBER_BUFFER = ESC_BUFFER + ESC_BUFFER_SIZE
- PARSE_BUFFER = NUMBER_BUFFER
- DEVICE_STATUS_BUFFER = PARSE_BUFFER + ESC_BUFFER_SIZE
- DEVICE_STATUS_SIZE = 11
- REASSIGNMENT_BUFFER = DEVICE_STATUS_BUFFER + DEVICE_STATUS_SIZE
-
- ; DISPOSABLE DATA
- ; ---------------
-
- SYNTAX LABEL BYTE
- DB "Syntax: ANSI [FAST | SLOW][ON | OFF][KON | KOFF][PON | POFF]" ;^
- if PCB ;^
- DB "[XON | XOFF]" ;^
- endif ;^
- DB CR,LF ;: ;^
- DB " [/B nnn][/C][/Q][/U][/T][/S][/P n]",CR,LF ;. ;@ ;:
- DB "FAST = direct screen writes; default",CR,LF ;:
- DB "SLOW = screen writes via BIOS",CR,LF ;:
- DB "ON/OFF = active/inactive; default is ON",CR,LF ;:
- DB "KON/KOFF = active/inactive reassignments; default is ON",CR,LF ;:
- DB "PON/POFF = active/inactive NEW reassignments; default is ON",CR,LF ;:
- if PCB ;^
- DB "XON/XOFF = active/inactive @Xnn color codes; default is ON",CR,LF ;^
- endif ;^
- DB "nnn = buffer size in bytes (0 - 60K) reserved for key reassignment; "
- DB "default 200",CR,LF
- DB "/Q = Quiet, no output when executed",CR,LF ;:
- DB "/U = Uninstall",CR,LF ;:
- DB "/T = Test if loaded",CR,LF ;$
- if PCB ;$
- DB "/S = Load stats from ANSICOM.SYS",CR,LF ;@
- endif ;$
- DB "/Pn = Protect n lines from scrolling at top" ;.
- CR_LF DB CR,LF,LF,"$"
-
- STATUS_MSG DB "Status: $"
- BUFFER_MSG DB CR,LF,"Buffer size: $"
- BYTES_FREE DB CR,LF,"Bytes free: $"
- ANSI_SYS_MSG DB "ANSI.SYS is installed so "
- NOT_INSTALLED DB "ANSI.COM not installed",CR,LF,"$"
- CON DB "CON"
- CON_OFFSET EQU 10
- QUIET DB 0 ;| Quiet Mode
- SYNTAX_FLAG DB 0 ;; Syntax Display Flag
- TEST_FLAG DW 0 ;^ For report use
-
- SIZE_MSG DB "Uninstall to change buffer size",CR,LF,LF,"$"
- UNLOAD_MSG DB "ANSI can't be uninstalled",CR,LF
- DB "Uninstall resident programs in reverse order",CR,LF,"$"
- NOT_ENOUGH DB "Not enough memory",CR,LF,"$"
- ALLOCATE_MSG DB "Memory allocation error",CR,LF,BELL,"$"
- INSTALL_MSG DB "Installed",CR,LF,"$"
- UNINSTALL_MSG DB "Uninstalled",CR,LF,"$"
- if PCB ;$
- NO_FILE_MSG DB "ANSICOM.SYS not found",CR,LF,"$" ;@
- FILE_ERROR_MSG DB "Error reading ANSICOM.SYS",CR,LF,"$" ;@
- FILE_NAME DB "ANSICOM.SYS",0 ;@
- endif ;$
- alrdy_installed db 0 ;^ Installed flag
- other_seg dw 0 ;^ Segment of installed code
- errmsg0 db "Need DOS 2.0 or greater!$" ;^
- errmsg14 db "Error using Int 2Fh!$" ;^
-
- INITIALIZE PROC NEAR
- ;--------------------------------------------------------------------;
- ; Search memory for a copy of our code, to see if already installed. ;
- ;--------------------------------------------------------------------;
-
- cld ;^
- mov ah,30h ;^ Get DOS version
- int 21h ;^
- xchg al,ah ;^ Swap major, minor numbers
- mov dx,offset errmsg0 ;^ Bad DOS version
- cmp ah,2 ;^ Run if DOS 2.0 or greater.
- jb jmp_msg_exit ;^
- mov dos_version,ax ;^ Save version number
- ;^
- ;^ See if a copy is already resident in memory. If > DOS 3.0, use int 2Fh.
- ;^
- mov byte ptr [start+2],0 ;^ Initialize fingerprint
- cmp dos_version,300h ;^ See if DOS 3.0 or later
- jb find_copy1 ;^ No, search the old way.
- mov cx,16 ;^ Try 16 different IDs.
- find_copy: ;^
- xor ax,ax ;^
- mov es,ax ;^
- mov ah,multiplex_id ;^ Load ID. Use Int 2Fh to
- int 2fh ;^ reach installed code so
- or al,al ;^ that we are compatible
- jne find_copy0 ;^ with 386 memory managers.
- push cs ;^
- pop es ;^ If AL not changed, ALIAS not
- jmp short find_copy4 ;^ installed.
- find_copy0: ;^
- push cx ;^
- call cmpheader ;^ See if really Alias by
- pop cx ;^ comparing file headers.
- je find_copy3 ;^
- inc multiplex_id ;^ ID used by another program.
- loop find_copy ;^ Change and try again.
- mov dx,offset errmsg14 ;^ All IDs taken, print error
- jmp_msg_exit: jmp msg_exit ;^ msg and exit.
- ;
- ;^ For DOS 2.x find the installed code the old fashioned way by scanning
- ;^ the memory control blocks.
- ;^
- find_copy1: ;^
- xor bx,bx ;^ zero BX for start
- mov ax,cs ;^ keep CS value in AX
- find_copy2: ;^
- inc bx ;^ increment search segment value
- mov es,bx ;^
- assume es:nothing ;^
- cmp ax,bx ;^ not installed if current
- je find_copy4 ;^ segment is found.
- call cmpheader ;^
- jne find_copy2 ;^ loop back if not found
- find_copy3: ;^
- inc alrdy_installed ;^ Set installed flag
- find_copy4: ;^
- mov other_seg,es ;^ Save seg of installed code
- ;^ CLD ;All string operations forward.
- ;^ MOV BX,OFFSET START ;Point to start of code.
- ;^ NOT BYTE PTR [BX] ;Change a byte so no false match.
- ;^ XOR DX,DX ;Start at segment zero.
- ;^ MOV AX,CS ;Store our segment in AX.
- ;^ NEXT_PARAG: INC DX ;Next paragraph.
- ;^ MOV ES,DX
- ;^ CMP DX,AX ;Is it our segment?
- ;^ JZ ANNOUNCE ;If yes, search is done.
- ;^ MOV SI,BX ;Else, point to our signature.
- ;^ MOV DI,BX ; and offset of possible match.
- ;^ MOV CX,16 ;Check 16 bytes for match.
- ;^ REP CMPSB
- ;^ JNZ NEXT_PARAG ;If no match, keep looking.
-
- ;------------------------------------------------;
-
- ANNOUNCE: ;|
- MOV SI,81H ;Point to command line.
- NEXT_CAP: LODSB ;Capitalize parameters.
- CMP AL,CR
- JZ PARSE
- CMP AL,"a"
- JB NEXT_CAP
- CMP AL,"z"
- JA NEXT_CAP
- AND BYTE PTR [SI - 1],5FH
- JMP SHORT NEXT_CAP
-
- ;------------------------------------------------;
-
- PARSE: MOV SI,81H ;Point to command line again.
- NEXT_PARA: XOR AX,AX ;Position in status parameters.
- MOV BX,4 ;Status parameters each 4 bytes.
- NEXT_STATUS: MOV DI,OFFSET PARAMETERS ;Point to "OFF ON SLOWFAST"
- ADD DI,AX ;Point to next parameter.
- ADD AX,BX
- CMP AX,LAST_PARAMETER ;:Check all 8 possible statuses
- JA CK_SWITCHES
- PUSH SI ;Save command line pointer.
- MOV CX,2 ;Check first two bytes for match.
- CMP AX,20 ;: 3 Bytes for
- JB Len_OK ;: KON | KOFF | PON | POFF
- INC CX ;: ;^ XON | XOFF
- Len_OK: ;:
- REP CMPSB
- POP SI ;Recover command line pointer.
- JNZ NEXT_STATUS
-
- DIV BL ;If match, divide offset by four.
- ;:
- ;: Next 12 lines of routine changed
- ;:
- ;: MOV CL,1 ;Set a bit to match offset.
- ;:NEXT_SHIFT: SHL CL,1
- ;: DEC AL
- ;: JNZ NEXT_SHIFT
- ;: SHR CL,1 ;Adjust.
- ;: MOV AH,STATUS_MASK ;Retrieve appropriate ON/OFF
- ;: CMP CL,ON ; or FAST/SLOW mask.
- ;: JBE ADD_STATUS
- ;: ROL AH,1
- ;: ROL AH,1
- ;:
- ;:ADD_STATUS: AND ES:STATUS,AH ;Mask off old status.
- ;: OR ES:STATUS,CL ;Add new status.
- ;:
- MOV CL,AL ;: ;^ place count in CL (1 - 10)
- PUSH DX ;^ Save Segment
- MOV AX,AND_MASK ;: ;^ Retrieve appropriate ON/OFF
- ;: FAST|SLOW|KON|KOFF|PON|POFF
- MOV DX,OR_MASK ;^ XON|XOFF
- DEC CL ;: ;^ Make 1 - 10 into 0 - 9
- JZ Skip_1 ;: In position already if zero
- SHL DX,CL ;: ;^ Shift bit into position
- Skip_1: SHR CL,1 ;: divide count by 2
- JZ Skip_2 ;: Nevermind
- ROL AX,CL ;: ;^ Shift Mask into position
- ROL AX,CL ;: ;^
- Skip_2: ;:
-
- AND ES:STATUS,AX ;^ Mask off old status.
- OR ES:STATUS,DX ;: ;^ Add new status.
- POP DX ;^ get back segment
- INC SI ;Bump command line pointer.
- INC SI
-
- CK_SWITCHES: LODSB ;Get a byte.
- CMP AL,CR ;Is it carriage return?
- JNE QUES ;$
- JMP INSTALL ;If yes, done here.
- QUES: CMP AL,"?" ;;Request for Syntax?
- JNE CK_SW ;; No -
- MOV BYTE PTR SYNTAX_FLAG, 1 ;; Yes-Show Syntax
- CK_SW: CMP AL,"/" ;;Is there a switch character?
- JNE NEXT_PARA ;;If no, keep looking.
- GOT_SWITCH: LODSB ;;Else, get the switch character.
- CMP AL,"B" ;Is it "B" ?
- JNZ CK_C ;If no, check "C".
- CALL CK_INSTALLED ;Else, see if already installed.
- JZ GET_SIZE ;If no, get buffer request size.
- MOV DX,OFFSET SIZE_MSG ;Else, display error message.
- CALL PRINT_STRING
- NEXT_PARA2: JMP SHORT NEXT_PARA
- GET_SIZE: CALL DECIMAL_INPUT ;Get number parameter.
- CMP BX,REASSIGNMENT_MAX ;If greater than maximum, use
- JBE STORE_BUFFER ; maximum, else use requested
- MOV BX,REASSIGNMENT_MAX ; size.
- STORE_BUFFER: MOV REASSIGNMENT_SIZE,BX
- ADD BX,OFFSET REASSIGNMENT_BUFFER ;Calculate end of buffer.
- MOV BUFFER_END,BX
- JMP NEXT_PARA ;;Too far for direct jump
-
- CK_C: CMP AL,"C" ;Is it "C" ?
- if PCB ;$
- JNZ CK_S ;@ If not, check "S".
- else ;$
- JNZ CK_P ;$ If not, check "P".
- endif ;$
- MOV ES:REASSIGN_END,OFFSET REASSIGNMENT_BUFFER ;Clear buffer
- JMP NEXT_PARA ;Else, next parmater.
- if PCB ;$
- CK_S: CMP AL,"S" ;@ Is It "S" ?
- JNZ CK_P ;. If not, check "P".
- CALL LOAD_STATS ;@ Yes, Load Stats
- JMP NEXT_PARA2 ;@ Next parameter (indirect)
- endif ;$
- CK_P: CMP AL,"P" ;. Is it "P" ?
- JNZ CK_Q ;|If not, check "Q".
- CMP BYTE PTR [SI], '*' ;$Use current row-1?
- JNE CK_PN ;$no
- PUSH SI ;$Get
- CALL GET_BIOS_DATA ;$ current
- MOV BL, ES:CURSOR_ROW ;$ row
- DEC BL ;$ -1
- POP SI ;$
- JMP CK_PS ;$
- CK_PN: CALL DECIMAL_INPUT ;. Get number of lines
- CK_PS: MOV ES:START_SCROLL,BL ;. Store the value
- JMP NEXT_PARA2 ;. Next parameter (indirect)
- CK_Q: CMP AL,"Q" ;|See if Quiet Mode
- JNE CK_U ;|If not, check "U".
- NOT QUIET ;|If yes turn on Quiet
- JMP NEXT_PARA ;Else, next parmater.
- CK_U: CMP AL,"U" ;Is it "U" ?
- JE DO_U ;If yes, try to uninstall.
- CMP AL,"T" ;; Test if Installed
- JE DO_U
- MOV BYTE PTR SYNTAX_FLAG, 1 ;; Syntax Error
- JMP NEXT_PARA ;Else, next parmater.
-
- ;------------------------------------------------;
-
- INSTALL:
- MOV DX,OFFSET SIGNATURE ;|Display our signature.
- CALL PRINT_STRING ;|
- CMP BYTE PTR SYNTAX_FLAG,0 ;;Display Syntax?
- JE SKIP_SYNTAX ;;No
- MOV DX,OFFSET SYNTAX ;|Yes, Display syntax.
- CALL PRINT_STRING ;|
- SKIP_SYNTAX: CALL STATUS_REPORT ;;|Display status.
- CALL CK_INSTALLED ;Check if already installed.
- JZ CK_AVAILABLE ;If no, see if enough memory.
- XOR AL,AL ;;Else, done.
- EXIT2: JMP EXIT ;Exit with ERRORLEVEL = 0.
-
- DO_U: CALL CK_INSTALLED ;Else, see if installed.
- MOV DX,OFFSET NOT_INSTALLED ;If no, exit with error message.
- JZ LILLY_PAD ;Too far for short jump.
- CMP AL,"T" ;;Was it a test
- MOV AX, STATUS ;$return switches as ;^
- JE EXIT2 ;;$Yes Too far for short jump.
- JMP UNINSTALL ;$Else, uninstall.
-
- ;--------------------------------;
- ; This is the install procedure. ;
- ;--------------------------------;
-
- CK_AVAILABLE: MOV BP,OFFSET REASSIGNMENT_BUFFER ;TSR ends at end
- ADD BP,REASSIGNMENT_SIZE ; of reassignment buffer.
- ADD BP,15 ;Round up.
- CMP BP,DS:[6] ;Buffer > PSP bytes in segment?
- MOV DX,OFFSET NOT_ENOUGH ;If yes, exit without installing
- JBE CK_ANSI ;@
- LILLY_PAD: JMP MSG_EXIT ;@with message
- CK_ANSI: MOV AX,3529H ;@Get undocumented INT 29 vector.
- INT 21H
- MOV SI,OFFSET CON ;Does it point to ANSI.SYS?
- MOV DI,CON_OFFSET ;Check by looking for "CON"
- MOV CX,3 ; as device name.
- REP CMPSB
- MOV DX,OFFSET ANSI_SYS_MSG ;Exit with error message if
- JZ LILLY_PAD ;ANSI.SYS loaded.
-
- MOV OLD_INT_29[0],BX ;Else save old interrupt.
- MOV OLD_INT_29[2],ES
- MOV DX,OFFSET ANSI_INT_29 ;Install new interrupt.
- MOV AX,2529H
- INT 21H
- MOV AX,3516H ;Get INT 16 vector.
- INT 21H
- MOV OLD_INT_16[0],BX ;Save old interrupt.
- MOV OLD_INT_16[2],ES
- MOV DX,OFFSET ANSI_INT_16 ;Install new interrupt.
- MOV AX,2516H
- INT 21H
- MOV AX,3521H ;Get DOS 21h interrupt.
- INT 21H
- MOV OLD_INT_21[0],BX ;Save old interrupt.
- MOV OLD_INT_21[2],ES
- MOV DX,OFFSET ANSI_INT_21 ;Install new interrupt.
- MOV AX,2521H
- INT 21H
- if PCB ;$
- MOV AX,3508H ;@ Get INT 08 vector.
- INT 21H ;@
- MOV OLD_INT_08[0],BX ;@ Save old interrupt.
- MOV OLD_INT_08[2],ES ;@
- MOV DX,OFFSET ANSI_INT_08 ;@ Install new interrupt.
- MOV AX,2508H ;@
- INT 21H ;@
- endif ;$
- cmp dos_version,300h ;^ See if we are using Int 2Fh
- jb install_3 ;^
- mov ax,352fh ;^ Get interrupt 2F (MUX)
- int 21h ;^ vector.
- mov word ptr [int2fh],bx ;^
- mov word ptr [int2fh+2],es ;^
- mov ax,252fh ;^ Point int 2F to internal
- mov dx,offset muxint ;^ routine.
- int 21h
- Install_3: ;^
-
- MOV AX,DS:[2CH] ;Get environment segment.
- MOV ES,AX
- MOV AH,49H ;Free up environment.
- INT 21H
-
- MOV DX,OFFSET INSTALL_MSG ;Display install message.
- CALL PRINT_STRING
- CALL FLUSH_END ;Setup the number buffer.
- MOV DX,BP ;Retrieve resident byte request.
- MOV CL,4
- SHR DX,CL ;Convert to paragraphs.
- MOV AX,3100H ;Return error code of zero.
- INT 21H ;Terminate but stay resident.
-
- ;-------------------------------------------------------------------;
- ; Exit. Return ERRORLEVEL code 0 if successful, 1 if unsuccessful. ;
- ;-------------------------------------------------------------------;
-
- MSG_EXIT: CALL PRINT_STRING
- ERROR_EXIT: MOV AL,1 ;ERRORLEVEL = 1.
- EXIT: MOV AH,4CH ;Terminate.
- INT 21H
-
- ;^-----------------------------------------------------------------------------
- ;^ CMPHEADER compares the first 16 bytes of this file with the segment
- ;^ pointed to by ES.
- ;^ Entry: DS - code segment
- ;^ ES - pointer to segment to compare
- ;^ Exit: ZF - 0 = segments match.
- ;^-----------------------------------------------------------------------------
- cmpheader proc near ;^
- mov si,offset start+2 ;^ Search this segment for ASCII
- mov di,si ;^ fingerprint.
- mov cx,16 ;^
- repe cmpsb ;^
- ret ;^
- cmpheader endp ;^
-
- ;---------------------------------------------------;
- ; This subroutine uninstalls the resident ANSI.COM. ;
- ;---------------------------------------------------;
-
- UNINSTALL: AND ES:STATUS,NOT ON ;Turn OFF ANSI, just in case
- OR ES:STATUS,OFF ; can't uninstall.
- MOV CX,ES ;Save segment in CX.
- MOV AX,3529H ;Get interrupt 29h.
- INT 21H
- CMP BX,OFFSET ANSI_INT_29 ;Has it been hooked by another?
- JNZ UNINSTALL_ERR2 ;@If yes, exit with error message.
- MOV BX,ES
- CMP BX,CX ;Is the segment vector same?
- JNZ UNINSTALL_ERR2 ;@If no, exit with error message.
- if PCB ;$
- MOV AX,3508H ;@Get interrupt 08h.
- INT 21H ;@
- CMP BX,OFFSET ANSI_INT_08 ;@Has it been hooked by another?
- JNZ UNINSTALL_ERR2 ;^;@If yes, exit with error message.
- MOV BX,ES ;@
- CMP BX,CX ;@Is the segment vector same?
- JNZ UNINSTALL_ERR2 ;^;@If no, exit with error message.
- endif ;$
- MOV AX,3516H ;Get interrupt 16h.
- INT 21H
- CMP BX,OFFSET ANSI_INT_16 ;Has it been hooked by another?
- JNZ UNINSTALL_ERR ;If yes, exit with error message.
- MOV BX,ES
- CMP BX,CX ;Is the segment vector same?
- UNINSTALL_ERR2:JNZ UNINSTALL_ERR ;If no, exit with error message.
-
- MOV AX,3521H ;Get interrupt 21h.
- INT 21H
- CMP BX,OFFSET ANSI_INT_21 ;Has it been hooked by another?
- JNZ UNINSTALL_ERR ;If yes, exit with error message.
- MOV BX,ES
- CMP BX,CX ;Is the segment vector same?
- JNZ UNINSTALL_ERR ;If no, exit with error message.
-
- MOV AH,49H ;Return memory to system pool.
- INT 21H
- MOV DX,OFFSET ALLOCATE_MSG
- JC MSG_EXIT ;Display message if problem.
-
- lds dx,es:[int2fh] ;^ Get old interrupt 2F vector
- cmp dx,-1 ;^ See if Int used
- je remove_1 ;^ No, skip check of Int 2F
- mov ax,252fh ;^ Set interrupt
- int 21h ;^
- remove_1: ;^
- MOV DX,ES:OLD_INT_29[0] ;Restore old INT 29.
- MOV DS,ES:OLD_INT_29[2]
- MOV AX,2529H
- INT 21H
- if PCB ;$
- MOV DX,ES:OLD_INT_08[0] ;@Restore old INT 08.
- MOV DS,ES:OLD_INT_08[2] ;@
- MOV AX,2508H ;@
- INT 21H ;@
- endif ;$
- MOV DX,ES:OLD_INT_16[0] ;Restore old INT 16.
- MOV DS,ES:OLD_INT_16[2]
- MOV AX,2516H
- INT 21H
- MOV DX,ES:OLD_INT_21[0] ;Restore old INT 21.
- MOV DS,ES:OLD_INT_21[2]
- MOV AX,2521H
- INT 21H
-
- PUSH CS
- POP DS ;Point to our data.
- MOV DX,OFFSET UNINSTALL_MSG ;Display uninstall message.
- CALL PRINT_STRING
- OR AL,AL ;Exit with ERRORLEVEL = 0.
- JMP EXIT
-
- UNINSTALL_ERR: MOV ES,CX ;If error, display OFF status.
- CALL STATUS_REPORT
- MOV DX,OFFSET UNLOAD_MSG ;And exit with error message.
- JMP MSG_EXIT
- INITIALIZE ENDP
-
- ;--------------------------------------------------;
- ; INPUT: SI points to parameter start. ;
- ; OUTPUT: SI points to parameter end; BX = number. ;
- ;--------------------------------------------------;
-
- DECIMAL_INPUT PROC NEAR
- XOR BX,BX ;Start with zero as number.
- NEXT_DECIMAL: LODSB ;Get a character.
- CMP AL,CR ;Carriage return?
- JZ ADJUST_DEC ;If yes, done here.
- CMP AL,"/" ;Forward slash?
- JZ ADJUST_DEC ;If yes, done here.
- SUB AL,"0" ;ASCII to binary.
- JC NEXT_DECIMAL ;If not between 0 and 9, skip.
- CMP AL,9
- JA NEXT_DECIMAL
- CBW ;Convert byte to word.
- XCHG AX,BX ;Swap old and new number.
- MOV CX,10 ;Shift to left by multiplying
- MUL CX ; last entry by ten.
- JC DECIMAL_ERROR ;If carry, too big.
- ADD BX,AX ;Add new number and store in BX.
- JNC NEXT_DECIMAL ;If not carry, next number.
- DECIMAL_ERROR: MOV BX,-1 ;Else, too big; return -1.
-
- ADJUST_DEC: DEC SI ;Adjust pointer.
- RET
- DECIMAL_INPUT ENDP
-
- ;-------------------------------------------------------;
- ; OUTPUT: ZR = 1 if not installed; ZR = 0 if installed. ;
- ;-------------------------------------------------------;
-
- CK_INSTALLED: PUSH AX ;;
- MOV AX,ES
- MOV BX,CS
- CMP AX,BX ;Compare segments.
- POP AX ;;
- RET
-
- ;------------------------------------------------;
-
- STATUS_REPORT: MOV DX,OFFSET STATUS_MSG
- CALL PRINT_STRING ;Display "Status: ".
- MOV BX,ES:STATUS ;^ Status is now a Word
- MOV TEST_FLAG,1 ;^ re-ran out of registers
- NEXT_REPORT: TEST BX,TEST_FLAG ;^ Check this status flag
- JZ LOOP_STATUS
-
- MOV DX,TEST_FLAG ;^ We need a copy to play with
- ;:
- ;: Next 9 Lines changed
- ;:
- ;: MOV AX,-1
- ;:NEXT_BIT: INC AX
- ;: SHR DL,1
- ;: JNC NEXT_BIT
- ;: SHL AX,1
- ;: SHL AX,1
- ;: MOV SI,OFFSET PARAMETERS ;Display appropriate ON or OFF,
- ;: ADD SI,AX ; SLOW or FAST.
- ;: MOV CX,4
- ;:
- MOV SI,OFFSET PARAMETERS ;:Display appropriate ON or OFF,
- ;: SLOW|FAST. KON|KOFF|PON|POFF
- MOV CX,4 ;:Each four characters long
- NEXT_BIT: SHR DX,1 ;: ;^Is this our Word?
- JC REPORT ;:Yes - Print it
- ADD SI,CX ;:No - Skip over it
- JMP NEXT_BIT ;:test the next bit
- REPORT: LODSB
- CALL PRINT_CHAR
- LOOP REPORT
- MOV AL, " " ;: Space words
- CALL PRINT_CHAR ;:
-
- LOOP_STATUS: SHL TEST_FLAG,1 ;^
- TEST TEST_FLAG,03FFH ;^
- JNZ NEXT_REPORT ;: ;^ Check all 10 bits
- ;:
- MOV DX,OFFSET BUFFER_MSG ;Display "Buffer size: ".
- CALL PRINT_STRING
- MOV AX,ES:REASSIGNMENT_SIZE
- PUSH AX
- XOR BP,BP
- CALL DECIMAL_OUT ;Display the size.
- MOV DX,OFFSET BYTES_FREE ;Display "Bytes free: ".
- CALL PRINT_STRING
- POP AX
- ADD AX,OFFSET REASSIGNMENT_BUFFER
- SUB AX,ES:REASSIGN_END
- CALL DECIMAL_OUT ;Display the bytes free.
- MOV DX,OFFSET CR_LF
- CALL PRINT_STRING
- RET
-
- ;------------------------------------------------;
-
- PRINT_CHAR: MOV DL,AL
- MOV AH,2 ;Print character via DOS.
- OR AL,AL ;:Skip NULLs
- JNZ SHORT DOS_INT ;:
- RET ;:
-
- PRINT_STRING: MOV AH,9 ;Print string via DOS.
- DOS_INT: CMP QUIET,0 ;|Do we suppress output
- JNE NO_PRINT ;|Yes
- INT 21H ;|No
- NO_PRINT: ;|
- RET
- if PCB ;$
- LOAD_STATS: MOV DX,OFFSET FILE_NAME ;@ Stat filename
- MOV AX,3D00H ;@ Open File
- INT 21H ;@ DOS Interupt
- MOV DX,OFFSET NO_FILE_MSG ;@ Assume no file
- JNC OPEN_OK ;@ Ok, So far
- MSG_EXIT2: JMP MSG_EXIT ;@ No file found probably
- OPEN_OK: MOV BX,AX ;@ This is our Handle number
- PUSH DS ;@ Save DS
- PUSH ES ;@ Set ES to DS
- POP DS ;@
- MOV DX, OFFSET SUB_LIST ;@ Point to the Sub_List
- MOV CX, SUB_LENGTH ;@ Get the Length ot the List
- MOV AH,3FH ;@ Read from Handle
- INT 21H ;@ DOS Interupt
- POP DS ;@ Restore DS
- PUSHF ;@ Save results
- PUSH AX ;@
- MOV AH,3EH ;@ Close Handle
- INT 21H ;@ DOS Interupt
- POP AX ;@ Restore results
- POPF ;@
- MOV DX,OFFSET FILE_ERROR_MSG ;@ Assume an error occured
- JC MSG_EXIT2 ;@ Yep, it did
- XCHG AX,CX ;@ Swap Bytes Read
- JCXZ MSG_EXIT2 ;@ Something went wrong
- CMP AX,CX ;@ Did we read the full amount
- JNE MSG_EXIT2 ;@ No
- RET ;@ All went well!
- endif ;$
- _TEXT ENDS
- END START
-